package cn.somkit.fmt.action;

import cn.hutool.json.JSONUtil;
import cn.somkit.fmt.utils.OsInfoUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Controller
@RequestMapping("/download")
public class DownloadAction {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Value("${somkit.upload.path.windows}")
    private String windows_path;

    @Value("${somkit.upload.path.linux}")
    private String linux_path;

    @GetMapping("/index")
    public ModelAndView index(String keyboard) throws Exception{
        String path = OsInfoUtil.isWindows() ? windows_path :
                        OsInfoUtil.isLinux() ? linux_path : null;
        logger.info("获取文件存储路径：{}", path);
        assert path != null;
        File folder = new File(path);
        File[] listOfFiles = folder.listFiles();
        List<Map<String, Object>> list = new ArrayList<>();

        if(listOfFiles != null){
            for (File file : listOfFiles) {
                if(!file.isFile()){
                    continue;
                }
                Map<String, Object> map = getObjectMap(file);
                list.add(map);
            }
        }
        if(StringUtils.hasText(keyboard) && !CollectionUtils.isEmpty(list)){
            list = list.stream().filter(map -> String.valueOf(map.get("filename"))
                    .contains(keyboard)).collect(Collectors.toList());
        }
        logger.info("关键词：{}，文件数量：{}", keyboard, list.size());
        ModelAndView mv = new ModelAndView();
        mv.setViewName("download");
        mv.addObject("files", list);
        mv.addObject("keyboard", keyboard);
        return mv;
    }

    private Map<String, Object> getObjectMap(File file) {
        BigDecimal filesize = BigDecimal.valueOf(file.length())
                .divide(BigDecimal.valueOf(1024 * 1024), 2, RoundingMode.HALF_UP);
        Long time = file.lastModified();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String filetime = format.format(time);
        Map<String, Object> map = new HashMap<>();
        map.put("filename", file.getName());
        map.put("filepath", file.getAbsolutePath());
        map.put("filesize", filesize);
        map.put("filetime", filetime);
        logger.info("文件信息：{}", JSONUtil.toJsonStr(map));
        return map;
    }

    @GetMapping(value = "/file", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public DeferredResult<ResponseEntity<StreamingResponseBody>> downloadFileByPath(String path, Boolean temp) throws Exception {
        final File file = new File(path);
        final DeferredResult<ResponseEntity<StreamingResponseBody>> result = new DeferredResult<>();

        if (!file.exists()) {
            result.setErrorResult(new RuntimeException("文件不存在"));
            return result;
        }

        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + URLEncoder.encode(file.getName(), StandardCharsets.UTF_8));
        headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(file.length()));
        StreamingResponseBody body = outputStream -> {
            try (InputStream inputStream = new FileInputStream(file)) {
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
                outputStream.flush();
            } catch (IOException e) {
                logger.error("IO错误：", e);
                throw new RuntimeException("IO错误: " + e.getMessage());
            } finally {
                // 尝试在流关闭后删除文件
                try {
                    if(temp){
                        Files.deleteIfExists(file.toPath());
                    }
                } catch (IOException e) {
                    // 记录日志或采取其他措施
                    logger.error("删除文件失败：{}", e.getMessage());
                }
            }
        };

        result.setResult(new ResponseEntity<>(body, headers, HttpStatus.OK));
        return result;
    }

    @PostMapping("/packZip")
    @ResponseBody
    public Map<String, Object> packZip(String filenames) throws Exception{
        try {
            String path = OsInfoUtil.isWindows() ? windows_path :
                    OsInfoUtil.isLinux() ? linux_path : null;
            assert path != null;
            //临时文件目录
            String temp = "temp";
            String zipPath = path + File.separator + temp;
            File zipFile =  new File(zipPath);
            if (!zipFile.exists()) zipFile.mkdirs();
            String zipName = String.valueOf(System.currentTimeMillis());
            String zipDir = zipPath + File.separator + zipName + ".zip";
            ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipDir));
            File folder = new File(path);
            File[] listOfFiles = folder.listFiles();
            assert listOfFiles != null;
            for (File file : listOfFiles) {
                if(!Arrays.asList(filenames.split(",")).contains(file.getName())){
                    continue;
                }
                FileInputStream fis = new FileInputStream(file);
                out.putNextEntry(new ZipEntry(file.getName()));
                int len;
                byte[] buffer = new byte[10240];
                while ((len = fis.read(buffer)) > 0){
                    out.write(buffer, 0, len);
                }
                out.closeEntry();
                fis.close();
            }
            out.close();
            Map<String, Object> result = new HashMap<>();
            result.put("path", zipDir);
            result.put("filename", zipName + ".zip");
            return result;
        }catch (Exception ex){
            ex.printStackTrace();
        }
        return null;
    }

    @PostMapping("/delete")
    @ResponseBody
    public String delete(String path) throws Exception{
        File file = new File(path);
        FileSystemUtils.deleteRecursively(file);
        return "删除成功";
    }

    @PostMapping("/batchDel")
    @ResponseBody
    public String batchDel(String filenames) throws Exception{
        String path = OsInfoUtil.isWindows() ? windows_path :
                OsInfoUtil.isLinux() ? linux_path : null;
        assert path != null;
        File folder = new File(path);
        File[] listOfFiles = folder.listFiles();
        assert listOfFiles != null;
        for (File file : listOfFiles) {
            if(!Arrays.asList(filenames.split(",")).contains(file.getName())){
                continue;
            }
            FileSystemUtils.deleteRecursively(file);
        }
        return "删除成功";
    }
}
